package cn.com.jenson.service.user.service.impl;

import cn.com.jenson.common.ImportVerifierVo;
import cn.com.jenson.common.SelectVo;
import cn.com.jenson.dao.user.bo.UserBo;
import cn.com.jenson.dao.user.searchBo.UserSearchBo;
import cn.com.jenson.dao.user.vo.UserVo;
import cn.com.jenson.entity.user.QUser;
import cn.com.jenson.entity.user.Role;
import cn.com.jenson.entity.user.User;
import cn.com.jenson.exception.BusinessException;
import cn.com.jenson.service.user.repository.RoleRepository;
import cn.com.jenson.service.user.repository.UserRepository;
import cn.com.jenson.service.user.service.UserService;
import cn.com.jenson.util.ListUtil;
import cn.com.jenson.util.MD5Util;
import cn.com.jenson.util.StringUtil;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    private static final String PASSWORD = "123456";

    @Resource
    UserRepository userRepository;

    @Resource
    JPAQueryFactory jpaQueryFactory;

    QUser qUser = QUser.user;

    @Resource
    RoleRepository roleRepository;

    @Override
    public Page<UserVo> pageAll(UserSearchBo userSearchBo) {
        JPAQuery<User> jpaQuery = jpaQueryFactory
                .selectFrom(qUser)
                .where(getWhere(userSearchBo));

        List<UserVo> userVoList = new UserVo()
                .fromEntities(
                        jpaQuery
                                .offset(userSearchBo.getPageRequest().getOffset())
                                .limit(userSearchBo.getPageRequest().getPageSize())
                                .fetch(),
                        UserVo.class
                );

        supplement(userVoList);
        return new PageImpl<>(userVoList, userSearchBo.getPageRequest(), jpaQuery.fetchCount());
    }

    @Override
    public List<UserVo> listAll(UserSearchBo userSearchBo) {
        JPAQuery<User> jpaQuery = jpaQueryFactory
                .selectFrom(qUser)
                .where(getWhere(userSearchBo));

        List<UserVo> userVoList = new UserVo()
                .fromEntities(
                        jpaQuery.fetch(),
                        UserVo.class
                );
        supplement(userVoList);
        return userVoList;
    }

    @Override
    public UserVo get(UserSearchBo userSearchBo) throws InstantiationException, IllegalAccessException {
        User user = userRepository.findByIdAndDeleted(userSearchBo.getId(), false).orElseThrow(
                () -> new BusinessException("未找到id为 " + userSearchBo.getId() + "的用户"));
        UserVo userVo = new UserVo().fromEntity(user, UserVo.class);
        supplement(userVo);
        return userVo;
    }

    @Override
    public BooleanExpression getWhere(UserSearchBo userSearchBo) {
        BooleanExpression where = qUser.deleted.eq(false);
        where = where.and(qUser.account.ne("admin"));
        where = where.and(qUser.account.ne("dev"));
        return where;
    }

    @Override
    public UserVo edit(UserBo userBo) throws InstantiationException, IllegalAccessException {
        User user = new UserBo().toEntity(userBo, User.class);
        if (Objects.isNull(user.getId())) {
            if (Objects.isNull(user.getPassword())) {
                user.setPassword(PASSWORD);
            }
            user.setEncipher(StringUtil.randomString(32));
            user.setBalance(0.0);
            user.setPassword(MD5Util.cryptographicString(user.getPassword(), user.getEncipher()));
        } else {
            if (Objects.isNull(user.getPassword())) {
                user.setPassword(userRepository.findById(user.getId()).get().getPassword());
            } else {
                user.setPassword(MD5Util.cryptographicString(user.getPassword(), user.getEncipher()));
            }
        }
        user = userRepository.save(user);
        return new UserVo().fromEntity(user, UserVo.class);
    }

    @Override
    public List<UserVo> editAll(List<UserBo> userBos) {
        List<User> all = userRepository.findAll();
        AtomicInteger account = new AtomicInteger();
        if (all.size() > 0) {
            account.set(all.stream().distinct().collect(Collectors.toList()).get(0).getId());
        } else {
            account.set(3);
        }
        List<User> userList = new UserBo().toEntities(userBos, User.class)
                .stream().peek(user -> {
                    user.setAccount("D" + StringUtil.coverPosition("0", 5, account.get()));
                    account.getAndIncrement();
                    if (Objects.isNull(user.getPassword())) {
                        user.setPassword(PASSWORD);
                    }
                }).collect(Collectors.toList());
        userRepository.saveAll(userList);
        return null;
    }

    @Override
    public UserVo deleted(UserSearchBo userSearchBo) throws InstantiationException, IllegalAccessException {
        User user = userRepository.findByIdAndDeleted(userSearchBo.getId(), false)
                .orElseThrow(() -> new BusinessException("找不到id为" + userSearchBo.getId() + "的用户"));
        user.setDeleted(true);
        user = userRepository.save(user);
        return new UserVo().fromEntity(user, UserVo.class);
    }

    @Override
    public List<UserVo> deletedAll(List<UserSearchBo> userSearchBos) {
        List<Integer> ids = userSearchBos.stream().map(UserSearchBo::getId).collect(Collectors.toList());
        List<User> userList = userRepository.findByIdInAndDeleted(ids, false);
        userList.forEach(item -> {
            item.setDeleted(true);
        });
        userList = userRepository.saveAll(userList);
        return new UserVo().fromEntities(userList, UserVo.class);
    }

    @Override
    public List<ImportVerifierVo> importTemplateVerifiers() {
        return null;
    }

    @Override
    public void importTemplateDownload(HttpServletResponse response) throws IOException {

    }

    @Override
    public List<SelectVo<String, Integer, UserVo>> option() {
        List<UserVo> userVoList = new UserVo().fromEntities(
                userRepository.findByDeleted(false),
                UserVo.class
        );
        return userVoList.stream().map(item ->
                new SelectVo<>(item.getName(), item.getId(), item)
        ).collect(Collectors.toList());
    }

    @Override
    public void supplement(UserVo userVo) {
        List<UserVo> userVoList = ListUtil.objectToObjectList(userVo);
        supplement(userVoList);
    }

    @Override
    public void supplement(List<UserVo> userVos) {
        List<Role> roleList = roleRepository.findByIdInAndDeleted(
                userVos.stream().map(UserVo::getRoleIdList)
                        .flatMap(List::stream)
                        .distinct()
                        .collect(Collectors.toList()),
                false);

        userVos.forEach(item -> {
            item.setRoleList(
                    roleList.stream().filter(role ->
                            ListUtil.haveTheSameItem(item.getRoleIdList(),role.getId())
                    ).collect(Collectors.toList())
            );
        });
    }

    @Override
    public void supplement(Page<UserVo> userVos) {
        supplement(userVos.getContent());
    }
}
